package com.dify.knowledge.config;

import io.netty.channel.ChannelOption;
import io.netty.handler.timeout.ReadTimeoutHandler;
import io.netty.handler.timeout.WriteTimeoutHandler;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.client.reactive.ReactorClientHttpConnector;
import org.springframework.web.reactive.function.client.ExchangeFilterFunction;
import org.springframework.web.reactive.function.client.WebClient;
import reactor.core.publisher.Mono;
import reactor.netty.http.client.HttpClient;
import reactor.util.retry.Retry;

import java.time.Duration;
import java.util.concurrent.TimeUnit;

/**
 * WebClient配置类 - 用于调用Dify API
 */
@Configuration
public class WebClientConfig {

    private final DifyProperties difyProperties;

    public WebClientConfig(DifyProperties difyProperties) {
        this.difyProperties = difyProperties;
    }

    /**
     * App API WebClient - 用于Chat API（问答功能）
     */
    @Bean(name = "appWebClient")
    public WebClient appWebClient() {
        return createWebClient(difyProperties.getAppKey());
    }
    
    /**
     * Dataset API WebClient - 用于Knowledge API（知识库管理）
     */
    @Bean(name = "datasetWebClient")
    public WebClient datasetWebClient() {
        return createWebClient(difyProperties.getDatasetKey());
    }

    /**
     * 创建WebClient
     */
    private WebClient createWebClient(String apiKey) {
        HttpClient httpClient = HttpClient.create()
                .option(ChannelOption.CONNECT_TIMEOUT_MILLIS, difyProperties.getTimeout())
                .responseTimeout(Duration.ofMillis(difyProperties.getTimeout()))
                .doOnConnected(conn ->
                        conn.addHandlerLast(new ReadTimeoutHandler(difyProperties.getTimeout(), TimeUnit.MILLISECONDS))
                                .addHandlerLast(new WriteTimeoutHandler(difyProperties.getTimeout(), TimeUnit.MILLISECONDS)));

        return WebClient.builder()
                .baseUrl(difyProperties.getBaseUrl())
                .clientConnector(new ReactorClientHttpConnector(httpClient))
                .defaultHeader("Authorization", "Bearer " + apiKey)
                .defaultHeader("Content-Type", "application/json")
                .filter(retryFilter())
                .build();
    }

    /**
     * 重试过滤器
     */
    private ExchangeFilterFunction retryFilter() {
        return (request, next) -> next.exchange(request)
                .flatMap(clientResponse -> {
                    if (clientResponse.statusCode().is5xxServerError()) {
                        return Mono.error(new RuntimeException("Server error: " + clientResponse.statusCode()));
                    }
                    return Mono.just(clientResponse);
                })
                .retryWhen(Retry.backoff(difyProperties.getMaxRetries(), Duration.ofSeconds(1))
                        .maxBackoff(Duration.ofSeconds(5))
                        .filter(throwable -> throwable instanceof RuntimeException));
    }
}
